﻿var EffectsObject = function () {
    /*
        Built with jQuery 1.9.1 in mind.
        Hold the genreric hide and show effect that are used through out the tool.
    */
    var speed = 'slow';

    this.show = function (obj, jqObj, newHeight) {
        /*
            Shows the current object
            obj - [optional] the object to with the effect will be applied to. Must contain [object].root that holds the jQuery object for the root dom element of the object
            jqObj - [optional] the jQuery object, to who'm the effect will be applied to
            newHeight - [optional][int] the  height to with the news will be rendered to;
            
            Remarks:
            The default behaiviour is where this function is designed to be added to a object as a show call, where the object has been build with [this.dom] beeing the HTML element and the [this.root] beeing it's jQuery Element. The implementtation is as follows: ExampleObject.show = Utility.EffectsObject.show;
        */

        var This = this;
        if (typeof obj == 'object' && obj != null) {
            This = obj;
        }
        if (typeof jqObj != 'object' || jqObj == null) {
            jqObj = This.root;
        }

        var hasNewHeight, oldHeight = jqObj.stop(true).height(), oldOpacity = jqObj.css('opacity');
        hasNewHeight = typeof newHeight == 'number';

        jqObj.show().css({
            position: 'absolute'
			, top: '0px'
			, left: '0px'
			, height: 'auto'
			, width: jqObj.width() + 'px'
			, opacity: 0.01
        });

        if (!hasNewHeight)
            newHeight = jqObj.height();

        jqObj.css({
            position: 'static'
			, top: 'auto'
			, left: 'auto'
			, height: oldHeight + 'px'
			, width: 'auto'
			, opacity: oldOpacity
        }).animate({
            opacity: 1,
            height: newHeight + 'px'
        }, speed, null, function () {
            if (!hasNewHeight)
                jqObj.css({ height: 'auto' });
        });
    };
    this.hide = function (obj, jqObj, onCloseCall) {
        /*
            Hides the current object
            obj - [optional] the object to with the effect will be applied to. Must contain [object].root that holds the jQuery object for the root dom element of the object
            jqObj - [optional] the jQuery object, to who'm the effect will be applied to		
            onCloseCall - [function] the method that will be called	when the object is fully close
            
            Remarks:
            The default behaiviour is where this function is designed to be added to a object as a hide call, where the object has been build with [this.dom] beeing the HTML element and the [this.root] beeing it's jQuery Element. The implementtation is as follows: ExampleObject.hide = Utility.EffectsObject.hide;
        */
        var This = this;
        if (typeof obj == 'object' && obj != null) {
            This = obj;
        }
        if (typeof jqObj != 'object' || jqObj == null) {
            jqObj = This.root;
        }
        jqObj.stop(true).animate({
            opacity: 0,
            height: '0px'
        }, speed, null, function () {
            jqObj.hide();
            if (typeof onCloseCall == 'function') {
                onCloseCall();
            }
        });
    };
};
var Utility = new (function () {

    this.baseURI = './';

    this.Lang = {
        ShortMonth: ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"],
        FullMonth: ["January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"]
    };
    this.TimeMarkers = {
        t: {
            am: 'A',
            pm: 'P'
        },
        tt: {
            am: 'AM',
            pm: 'PM'
        }
    };

    this.dateFormat = 'dd/MM/yyyy'; //the default date format control for the [this.formatDate] call
    this.hasArabicNumbers = false; //controls if the tool shows numbers as Arabic numbers or not
    this.isRTL = false; //controls if the layout of the tools is RTL based or not
    this.Mouse = { //Holds the current Mouse position
        x: 0,
        y: 0
    };

    this.Effects = new EffectsObject();

    var This = this
		, frameCalls = []
		, IE_Version = null
    ;
    function _init() {
        document.onmousemove = getMousePos;
        document.ontouchmove = getMousePos;
        document.ontouchstart = getMousePos;
    }

    function getMousePos(e) {
        /*
            THIS == document
        */
        if (!e) var e = window.event;
        if (e == undefined)
            return;
        if (e.touches) {

            if (e.touches.length > 1)
                return;

            var touch = e.touches[0];
            if (typeof touch == 'object') {
                This.Mouse.x = touch.pageX;
                This.Mouse.y = touch.pageY;
            }
        } else {
            if (e.pageX || e.pageY) {
                This.Mouse.x = e.pageX;
                This.Mouse.y = e.pageY;
            } else if (e.clientX || e.clientY) {
                This.Mouse.x = e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft;
                This.Mouse.y = e.clientY + document.body.scrollTop + document.documentElement.scrollTop;
            }
        }
    }
    function frameCall() {
        /*
            The FrameCall loop function i.e. this function creates the internal frameCall event.
        */
        var index = frameCalls.length;
        while (index--) {
            frameCalls[index]();
        }
        setTimeout(function () { frameCall(); }, 40);
    }

    function getIE_Version() {
        /*
            Returns the current IE version. Returns -1 if the browser is not a IE.
        */
        if (!document.all) //if the browser is not a IE returns -1
            return -1;
        if (IE_Version != null) //if the browser version has already been found returns that
            return IE_Version;

        //Finds out the IE version
        var index
			, browser = navigator.userAgent
        ;

        index = browser.search('MSIE');
        if (index == -1)
            return -1;

        IE_Version = browser.substring(index + 4, browser.indexOf(';', index));
        IE_Version = Math.floor(parseFloat(IE_Version));
        return IE_Version;
    }
    this.getDocumentModeIE = function () {
        /*
            Returns the IE's DocumentMode for IE, for non IE -1 is returned.
        */
        if (document.all) {
            var version = getIE_Version(),
				documentMode = typeof document.documentMode == 'undefined' ? version : Math.floor(parseFloat(document.documentMode));
            return documentMode;
        }
        return -1;
    };

    this.MakeInlineBlockDOM = function (dom) {

        //makes the button into a inline-block element
        if (document.all) {
            if (this.getDocumentModeIE() < 8) {
                dom.style.zoom = 1.0;
                dom.style.display = 'inline';
            } else {
                dom.style.display = 'inline-block';
            }
        } else {
            dom.style.display = 'inline-block';
        }
    };

    this.addCssFile = function (url) {
        /*
            Adds a CSS file to the head
            url - String, the URL of the CSS file
        */
        if (typeof url != 'string')
            return;

        var head = document.getElementsByTagName('head')[0]
			, link = document.createElement('link')
        ;

        link.setAttribute('href', url);
        link.setAttribute('rel', 'stylesheet');
        link.setAttribute('type', 'text/css');

        if (typeof document.createStyleSheet == 'function')
            document.createStyleSheet(url);

        head.appendChild(link);
    };
    this.jQueryAjaxRetryCall = function (url, Settings, errorCall, retryAmmount) {
        /*
            Implements a jQuery Ajax call with a retry policy. 
            
            url - String, The URL on with the Ajax call will be made
            Settings - Object, The jQuery $.ajax() functions [settings] object
            errorCall - [Optional] function, the error call that will be called if the retry cycle did not get any data, if left unset will be replaced with the Settings.error call (if exists)
            retryAmmount - [Optional] Number, The ammount of retryed the function do, by default 1.
            
            Remarks: 
            Although it overwrites the [Settings.error] call douring the retrys you still can use this to get the errors. In essence is designed to be used as follows: Utility.jQueryAjaxRetryCall(url, Settings);
        */
        if (typeof retryAmmount != 'number')
            retryAmmount = 1;

        if (typeof errorCall != 'function') {
            if (typeof Settings.error == 'function') {
                errorCall = Settings.error;
            } else {
                errorCall = null;
            }
        }

        if (retryAmmount > 0) {
            Settings.error = function () {
                retryAmmount--;
                This.jQueryAjaxRetryCall(url, Settings, errorCall, retryAmmount);
            }
        } else {
            Settings.error = errorCall;
        }

        $.ajax(url, Settings);
    };

    this.isMouseOverDom = function (dom) {
        /*
            Returns TRUE of the Mouse is over the givven dom, otherwise returns FALSE.
            dom - HTML DOM Object, the DOM object above whom the mouse is supposed to be.
        */
        var obj = this.Dom.pos(dom);
        return !( //is the mouse over the icon
			this.Mouse.x < obj.x
			|| this.Mouse.x > obj.x + obj.width
			|| this.Mouse.y < obj.y
			|| this.Mouse.y > obj.y + obj.height
		);
    };
    this.addFrameCall = function (call) {
        /*
            Adds a call to the [frameCalls] array and activates the frame call loop if needed.
        */
        if (!frameCalls.length)
            frameCall();
        frameCalls.push(call);
    };

    this.blur = function () {
        /*
            Removes the focus from any element
        */
        document.documentElement.focus();
        document.documentElement.blur();
    };

    this.getArabicNumbers = function (str, useArabicNumbers) {
        /*
            Returns a converted string where all the latin numbers are turned into arabic numbers when the [this.hasArabicNumbers] has been set to TRUE
            str - String, the phrase whom numbers are to be converted.
            useArabicNumbers - [Optional] Boolean, Overwrites the [this.hasArabicNumbers]
        */
        if (typeof useArabicNumbers != 'boolean')
            useArabicNumbers = this.hasArabicNumbers;
        if (!useArabicNumbers)
            return str;
        if (typeof str != 'string')
            str = new String(str);
        var ret = "", str_char,
			index = str.length;
        while (index--) {

            str_char = str.charAt(index);
            switch (str_char) {
                case "1": str_char = "١"; break;
                case "2": str_char = "٢"; break;
                case "3": str_char = "٣"; break;
                case "4": str_char = "٤"; break;
                case "5": str_char = "٥"; break;
                case "6": str_char = "٦"; break;
                case "7": str_char = "٧"; break;
                case "8": str_char = "٨"; break;
                case "9": str_char = "٩"; break;
                case "0": str_char = "٠"; break;
                default:
            }
            ret = str_char + ret;
        }
        return ret;
    };

    this.formatDate = function (date, strDateFormat, useArabicNumbers) {
        /*
            Returns a formated string where a Date object (or a object reprecenting a date) is turned into a custom formated string with ASP.NET date format.
            
            date - Object, contains
                day - integer, the day of the date
                month - integer, the month of the date (1-12)
                year - integer, the year of the date
                minutes - integer, the minutes of the date
                hours - integer, the hour of the date
                
                NB! - the date object can be a normal JS [Date] object as well
            strDateFormat - [Optional] String, the ASP.NET custom Date format into with the [date] object will be converted. Overwrites the [this.dateFormat].
            useArabicNumbers - [Optional] Boolean, if set to TRUE turns all the numbers into arabic numbers.  
            
            Format markers:
            dd - day in a two digit format
            d - day in a single digit format
            MMM - month in a three letter format
            MM - month in a two digit format
            M - month in a single digit format
            m - minutes in a single digit format
            mm - minutes in two digit format
            HH - 24 hours in two digit format
            H - 24 hours in singe digit format
            hh - 12 hours in two digit format
            h - 12 hours in singe digit format
            t - first letter of the AM/PM marker
            tt - AM/PM marker
            yyyy - year in a four digit format
            yy - year in a two digit format
        */
        if (typeof date != 'object') {
            return '';
        }
        if (typeof date.day != 'number') {
            var obj = new Object();
            obj.day = date.getDate();
            obj.month = date.getMonth() + 1;
            obj.year = date.getFullYear();
            obj.minutes = date.getMinutes();
            obj.hours = date.getHours();

            date = obj;
        }

        switch (typeof useArabicNumbers) {
            case 'boolean':
            case 'number':
                break;
            default:
                useArabicNumbers = This.hasArabicNumbers;
                break;
        }

        var format = typeof strDateFormat == 'string' ? strDateFormat : This.dateFormat,
			ret = "", i, markerType = "", temp, marker = "";

        for (i = 0; i < format.length; i++) {
            temp = format.charAt(i);

            if (temp != markerType && markerType.length) {

                markerType = getDatePartFromMarker(date, marker, useArabicNumbers);
                if (typeof markerType == 'string')
                    ret += markerType;
                else
                    ret += marker;

                markerType = marker = '';
            }

            switch (temp) {
                case 'd':
                    markerType = 'd';
                    marker += markerType;
                    break;
                case 'M':
                    markerType = 'M';
                    marker += markerType;
                    break;
                case 'y':
                    markerType = 'y';
                    marker += markerType;
                    break;
                case 'm':
                    markerType = 'm';
                    marker += markerType;
                    break;
                case 'H':
                    markerType = 'H';
                    marker += markerType;
                    break;
                case 'h':
                    markerType = 'h';
                    marker += markerType;
                    break;
                case 't':
                    markerType = 't';
                    marker += markerType;
                    break;
                default:
                    ret += temp;
                    break;
            }
        }

        if (marker.length) {
            markerType = getDatePartFromMarker(date, marker, useArabicNumbers);
            if (typeof markerType == 'string')
                ret += markerType;
            else
                ret += marker;
        }

        return ret;
    };

    function getDatePartFromMarker(Date, strMarker, useArabicNumbers) {

        var ret = '';
        switch (strMarker) {
            case "dd": if (Date.day < 10) ret += "0";
            case "d": ret += new String(Date.day); break;

            case "MM": if (Date.month < 10) ret += "0";
            case "M": ret += new String(Date.month); break;

            case "MMM": ret += This.Lang.ShortMonth[Date.month - 1]; break;
            case "MMMM": ret += This.Lang.FullMonth[Date.month - 1]; break;

            case "yy":
                var twoNumberYear = String(Date.year);
                ret += twoNumberYear.substring(twoNumberYear.length - 2);
                break;
            case "yyyy": ret += new String(Date.year); break;

            case "mm": if (Date.minutes < 10) ret += "0";
            case "m": ret += new String(Date.minutes); break;

            case "HH": if (Date.hours < 10) ret += "0";
            case "H": ret += new String(Date.hours); break;

            case "hh": if (Date.hours < 10) ret += "0";
            case "h":
                switch (Date.hours) {
                    case 0:
                        ret += "12";
                        break;
                    case 12:
                        ret += "12";
                        break;
                    default:
                        ret += new String(Date.hours > 12 ? Date.hours - 12 : Date.hours);
                        break;
                }
                break;

            case "t": ret += Date.hours > 11 ? This.TimeMarkers.t.pm : This.TimeMarkers.t.am; break;
            case "tt": ret += Date.hours > 11 ? This.TimeMarkers.tt.pm : This.TimeMarkers.tt.am; break;
            default:
                ret = null;
                break;
        }

        return This.getArabicNumbers(ret, useArabicNumbers);
    }

    this.Dom = {
        xy: function (obj) {

            var ret = new Object();
            ret.x = 0;
            ret.y = 0;
            ret.scrollLeft = 0;
            ret.scrollTop = 0;

            if (obj.offsetParent) {
                do {
                    ret.x += parseInt(obj.offsetLeft);
                    ret.y += parseInt(obj.offsetTop);

                    ret.scrollLeft += parseInt(obj.scrollLeft);
                    ret.scrollTop += parseInt(obj.scrollTop);

                } while (obj = obj.offsetParent);
            }

            ret.x -= ret.scrollLeft;
            ret.y -= ret.scrollTop;

            var temp = parseInt(document.body.scrollLeft);
            ret.x += temp;
            ret.scrollLeft -= temp;

            temp = parseInt(document.body.scrollTop);
            ret.y += temp;
            ret.scrollTop -= temp;

            return ret;
        },
        xyID: function (strID) {

            var obj = document.getElementById(strID);
            return This.Dom.xy(obj);
        },
        pos: function (obj) {
            var ret = This.Dom.xy(obj);
            ret.width = parseFloat(obj.offsetWidth);
            ret.height = parseFloat(obj.offsetHeight);
            return ret;
        },
        posID: function (strID) {
            var obj = document.getElementById(strID);
            return This.Dom.pos(obj);
        },
        widthHeight: function (dom) {
            var ret = new Object();
            ret.width = parseFloat(dom.offsetWidth);
            ret.height = parseFloat(dom.offsetHeight);
            return ret;
        },
        widthHeightID: function (ID) {
            var dom = document.getElementById(ID);
            return This.Dom.widthHeight(dom);
        }
    };
    this.getWindowDimentions = function () {

        var ret = new Object();
        ret.width = 0;
        ret.height = 0;

        if (typeof (window.innerWidth) == 'number') {
            //Non-IE
            ret.width = window.innerWidth;
            ret.height = window.innerHeight;
        } else if (document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
            //IE 6+ in 'standards compliant mode'
            ret.width = document.documentElement.clientWidth;
            ret.height = document.documentElement.clientHeight;
        } else if (document.body && (document.body.clientWidth || document.body.clientHeight)) {
            //IE 4 compatible
            ret.width = document.body.clientWidth;
            ret.height = document.body.clientHeight;
        }

        ret.scrollLeft = document.documentElement.scrollLeft;
        ret.scrollTop = document.documentElement.scrollTop;
        if (ret.scrollLeft == ret.scrollTop && ret.scrollLeft == 0) {
            //Webkit browsers hold the scroller info in the document.body and not the document.documentElement
            ret.scrollLeft = document.body.scrollLeft;
            ret.scrollTop = document.body.scrollTop;
        }
        return ret;
    };
    _init();
})();